package com.itheima.sfbx.insurance.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.itheima.sfbx.file.feign.FileBusinessFeign;
import com.itheima.sfbx.framework.commons.constant.basic.SuperConstant;
import com.itheima.sfbx.framework.commons.constant.category.CategoryConstant;
import com.itheima.sfbx.framework.commons.constant.insure.InsureConstant;
import com.itheima.sfbx.framework.commons.dto.basic.TreeItemVO;
import com.itheima.sfbx.framework.commons.dto.basic.TreeVO;
import com.itheima.sfbx.framework.commons.exception.ProjectException;
import com.itheima.sfbx.framework.commons.utils.BeanConv;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import com.itheima.sfbx.framework.commons.utils.ExceptionsUtil;
import com.itheima.sfbx.framework.commons.utils.NoProcessing;
import com.itheima.sfbx.insurance.constant.CategoryCacheConstant;
import com.itheima.sfbx.insurance.dto.CategoryCoefficentVO;
import com.itheima.sfbx.insurance.dto.CategoryConditionVO;
import com.itheima.sfbx.insurance.dto.CategorySafeguardVO;
import com.itheima.sfbx.insurance.dto.CategoryVO;
import com.itheima.sfbx.insurance.enums.CategoryEnum;
import com.itheima.sfbx.insurance.mapper.CategoryMapper;
import com.itheima.sfbx.insurance.pojo.Category;
import com.itheima.sfbx.insurance.pojo.CategoryCoefficent;
import com.itheima.sfbx.insurance.pojo.CategoryCondition;
import com.itheima.sfbx.insurance.pojo.CategorySafeguard;
import com.itheima.sfbx.insurance.service.ICategoryCoefficentService;
import com.itheima.sfbx.insurance.service.ICategoryConditionService;
import com.itheima.sfbx.insurance.service.ICategorySafeguardService;
import com.itheima.sfbx.insurance.service.ICategoryService;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bind.annotation.Super;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description：保险分类服务实现类
 */
@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    @Autowired
    ICategoryConditionService categoryConditionService;

    @Autowired
    ICategoryCoefficentService categoryCoefficentService;

    @Autowired
    ICategorySafeguardService categorySafeguardService;

    private LambdaQueryWrapper<Category> queryWrapper(CategoryVO vo){
        LambdaQueryWrapper<Category> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StrUtil.isNotBlank(vo.getParentCategoryNo()),Category::getParentCategoryNo,vo.getParentCategoryNo());
        lqw.eq(StrUtil.isNotBlank(vo.getCategoryNo()),Category::getCategoryNo,vo.getCategoryNo());
        lqw.like(StrUtil.isNotBlank(vo.getCategoryName()),Category::getCategoryName,vo.getCategoryName());
        lqw.eq(StrUtil.isNotBlank(vo.getCategoryType()),Category::getCategoryType,vo.getCategoryType());
        lqw.eq(StrUtil.isNotBlank(vo.getDataState()),Category::getDataState,vo.getDataState());
        lqw.eq(StrUtil.isNotBlank(vo.getLeafNode()),Category::getLeafNode,vo.getLeafNode());
        lqw.eq(StrUtil.isNotBlank(vo.getShowIndex()),Category::getShowIndex,vo.getShowIndex());
        return lqw;
    }

    private List<CategoryVO> buildVoList(List<Category> categoryList){
        List<CategoryVO> voList = BeanConv.toBeanList(categoryList,CategoryVO.class);
        Set<String> noSet = categoryList.stream().map(Category::getCategoryNo).collect(Collectors.toSet());
        //处理condition
        List<CategoryCondition> conditionList = categoryConditionService.lambdaQuery()
                .in(CategoryCondition::getCategoryNo, noSet)
                .eq(CategoryCondition::getDataState, SuperConstant.DATA_STATE_0)
                .list();
        Map<String, List<CategoryCondition>> condtionMap = conditionList.stream().collect(Collectors.groupingBy(CategoryCondition::getCategoryNo));
        //处理safeguard
        List<CategorySafeguard> safeguardList = categorySafeguardService.lambdaQuery()
                .in(CategorySafeguard::getCategoryNo, noSet)
                .eq(CategorySafeguard::getDataState, SuperConstant.DATA_STATE_0)
                .list();
        Map<String, List<CategorySafeguard>> safeguardMap = safeguardList.stream().collect(Collectors.groupingBy(CategorySafeguard::getCategoryNo));
        //处理coefficent
        List<CategoryCoefficent> coefficentList = categoryCoefficentService.lambdaQuery()
                .in(CategoryCoefficent::getCategoryNo, noSet)
                .eq(CategoryCoefficent::getDataState, SuperConstant.DATA_STATE_0)
                .list();
        Map<String, List<CategoryCoefficent>> coefficentMap = coefficentList.stream().collect(Collectors.groupingBy(CategoryCoefficent::getCategoryNo));
        for (CategoryVO vo : voList) {
            List<CategoryCondition> conditions = condtionMap.get(vo.getCategoryNo());
            vo.setCategoryConditionVOs(BeanConv.toBeanList(conditions,CategoryConditionVO.class));
            List<CategorySafeguard> safeguards = safeguardMap.get(vo.getCategoryNo());
            vo.setCategorySafeguardVOs(BeanConv.toBeanList(safeguards, CategorySafeguardVO.class));
            List<CategoryCoefficent> coefficents = coefficentMap.get(vo.getCategoryNo());
            vo.setCategoryCoefficentVOs(BeanConv.toBeanList(coefficents,CategoryCoefficentVO.class));
        }
        return voList;
    }

    @Override
    public Page<CategoryVO> findPage(CategoryVO categoryVO, int pageNum, int pageSize) {
        //1.写sql
        LambdaQueryWrapper<Category> lqw = queryWrapper(categoryVO);
        Page<Category> page = this.page(new Page<>(pageNum, pageSize), lqw);
        List<Category> categoryList = page.getRecords();
        if (CollUtil.isEmpty(categoryList)) {
            //如果没数据，那就不用去找对应的关系
            return BeanConv.toPage(page,CategoryVO.class);
        }
        //想要处理分类对应的筛选项、保障项、系数项，得先拿到对应的
        //sql：select * from tab_category_coefficent where category_no in ()
        //list、one、page、count
        List<CategoryVO> voList = buildVoList(categoryList);
        Page<CategoryVO> voPage = BeanConv.toPage(page, CategoryVO.class);
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    @Transactional
    public CategoryVO save(CategoryVO categoryVO) {
        String categoryNo = this.createCategoryNo(categoryVO.getParentCategoryNo());
        Category category = BeanConv.toBean(categoryVO, Category.class);
        category.setCategoryNo(categoryNo);
        this.save(category);
        return BeanConv.toBean(category,CategoryVO.class);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(CategoryVO categoryVO) {
        //分类和筛选项、系数项、保障项都是有关系的
        //1.先保存分类
        Category old = getById(categoryVO.getId());
        if(old==null){
            //原数据不存在
            throw new ProjectException(CategoryEnum.UPDATE_FAIL);
        }
        Category category = BeanConv.toBean(categoryVO, Category.class);
        updateById(category);
        //2.处理分类对应的关系表
        //先删
        categorySafeguardService.deleteByCategoryNo(categoryVO.getCategoryNo());
        categoryCoefficentService.deleteByCategoryNo(categoryVO.getCategoryNo());
        categoryConditionService.deleteByCategoryNo(categoryVO.getCategoryNo());
        //新增
        //处理关联关系
        List<CategorySafeguardVO> safeguardVOs = categoryVO.getCategorySafeguardVOs();
        if(CollUtil.isNotEmpty(safeguardVOs)){
            List<CategorySafeguard> safeguardList = safeguardVOs.stream().map(vo -> {
                CategorySafeguard bean = BeanConv.toBean(vo, CategorySafeguard.class);
                bean.setCategoryNo(categoryVO.getCategoryNo());
                return bean;
            }).collect(Collectors.toList());
            categorySafeguardService.saveBatch(safeguardList);
        }

        List<CategoryConditionVO> conditionVOs = categoryVO.getCategoryConditionVOs();
        if (CollUtil.isNotEmpty(conditionVOs)) {
            List<CategoryCondition> conditions = conditionVOs.stream().map(vo -> {
                CategoryCondition bean = BeanConv.toBean(vo, CategoryCondition.class);
                bean.setCategoryNo(categoryVO.getCategoryNo());
                return bean;
            }).collect(Collectors.toList());
            categoryConditionService.saveBatch(conditions);
        }

        List<CategoryCoefficentVO> coefficentVOs = categoryVO.getCategoryCoefficentVOs();
        if(CollUtil.isNotEmpty(coefficentVOs)){
            List<CategoryCoefficent> coefficents = coefficentVOs.stream().map(vo -> {
                CategoryCoefficent bean = BeanConv.toBean(vo, CategoryCoefficent.class);
                bean.setCategoryNo(categoryVO.getCategoryNo());
                return bean;
            }).collect(Collectors.toList());
            categoryCoefficentService.saveBatch(coefficents);
        }

        return true;
    }

    @Override
    @Transactional
    public Boolean delete(String[] checkedIds) {
        List<Long> idList = new ArrayList<>();
        for (String checkedId : checkedIds) {
            idList.add(Long.parseLong(checkedId));
        }
        List<Category> categories = listByIds(idList);
        //删除关联的分类保障项、分类筛选项、分类系数项信息
        if (EmptyUtil.isNullOrEmpty(categories)){
            List<String> categoryNos = categories.stream().map(Category::getCategoryNo).collect(Collectors.toList());
            categoryConditionService.deleteByCategoryNos(categoryNos);
            categoryCoefficentService.deleteByCategoryNos(categoryNos);
            categorySafeguardService.deleteByCategoryNos(categoryNos);
        }
        return removeByIds(idList);
    }

    @Override
    public List<CategoryVO> findList(CategoryVO categoryVO) {
        LambdaQueryWrapper<Category> lqw = queryWrapper(categoryVO);
        List<Category> list = this.list(lqw);
        //处理层级nodeFloors
        List<Category> newList = new ArrayList<>();
        if(CollUtil.isNotEmpty(categoryVO.getNodeFloors())){
            //需要处理
            for (Category category : list) {
                //根据NoProcessing工具类，得到的长度来判断具体是那一层
                long level = NoProcessing.processString(category.getCategoryNo()).length()/3 - 1;
                if (categoryVO.getNodeFloors().contains(level)) {
                    //说明是这一层的
                    newList.add(category);
                }
            }
        }else{
            //不需要处理
            newList.addAll(list);
        }
        List<CategoryVO> voList = buildVoList(newList);
        return voList;
    }



    @Override
    public TreeVO categoryTreeVO(String parentCategoryNo, String categoryType,String[] checkedCategoryNos) {
        //我们已经确定返回树形结构，使用TreeVO来返回，TreeVO有items就作为第一层，TreeVO本身做为根节点
        //实现树形的固定套路
        //1.先确定根节点
        String rootNo = StrUtil.isBlank(parentCategoryNo)?SuperConstant.ROOT_PARENT_ID:parentCategoryNo;
        //2.根据根节点，查出下面所有的子节点
        //sql：select * from tab_category where category_no like ? and category_type = ?
        List<Category> list = lambdaQuery()
                .likeRight(Category::getCategoryNo, NoProcessing.processString(rootNo))
                .eq(StrUtil.isNotBlank(categoryType), Category::getCategoryType, categoryType)
                .eq(Category::getDataState, SuperConstant.DATA_STATE_0)
                .list();
        //如果list为空，说明根本没有子节点
        if (CollUtil.isEmpty(list)) {
            return TreeVO.builder().build();
        }
        //3.先确定一层父子关系
        //3.1把list转换成TreeVO需要的item
        List<TreeItemVO> items = list.stream().map(cate->{
            return TreeItemVO.builder()
                    .id(cate.getCategoryNo())
                    .parentId(cate.getParentCategoryNo())
                    .label(cate.getCategoryName())
                    .build();
        }).collect(Collectors.toList());
        //3.2整合父子关系。产出一个Map，的key：父ID，value：这个父ID对应的子节点的集合
        Map<String, List<TreeItemVO>> treeMap = items.stream().collect(Collectors.groupingBy(TreeItemVO::getParentId));
        //3.3遍历把父子关系给挂上
        for (TreeItemVO item : items) {
            //找孩子
            List<TreeItemVO> children = treeMap.get(item.getId());
            item.setChildren(children);
        }
        //4.确定根节点
        //找第一层
        List<TreeItemVO> first = treeMap.get(rootNo);
        return TreeVO.builder()
                .items(first)
                .build();
    }

    @Override
    public String createCategoryNo(String parentCategoryNo) {
        CategoryVO categoryVO = CategoryVO.builder()
            .parentCategoryNo(parentCategoryNo)
            .build();
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Category::getParentCategoryNo,parentCategoryNo);
        List<Category> categoryList = list(queryWrapper);
        //无下属节点则创建下属节点
        if (EmptyUtil.isNullOrEmpty(categoryList)){
            return NoProcessing.createNo(parentCategoryNo,false);
        //有下属节点则累加下属节点
        }else {
            Long categoryNo = categoryList.stream()
                .map(category -> { return Long.valueOf(category.getCategoryNo());})
                .max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(categoryNo),true);
        }
    }

    /**
     * 人种榜险种榜分类
      * @param type
     */
    @Override
    public List<CategoryVO> categoryCheckRule(String type) {
        //判断是否是险种榜
        if(InsureConstant.checkIsInsureType(type)){
            List<CategoryVO> res = new ArrayList<>();
            //获取所有的险种榜
            List<String> allCheckRule = InsureConstant.getAllCheckRule();
            allCheckRule.forEach(e->{
                CategoryVO categoryVO = CategoryVO.builder().categoryNo(e).categoryName(InsureConstant.getRuleNameById(e)).build();
                res.add(categoryVO);
            });
            return res;
        }else{
            //说明是人种榜
            List<String> categoryNames = Arrays.asList("成年人", "少儿", "老人");
            LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(Category::getCategoryName,categoryNames);
            queryWrapper.eq(Category::getDataState,SuperConstant.DATA_STATE_0);
            List<CategoryVO> res = BeanConv.toBeanList(list(queryWrapper), CategoryVO.class);
            return res;
        }
    }
}
